import numpy as np
import matplotlib.pyplot as plt
import operator

from numpy.matlib import zeros


# group_test = np.array([[0.0, 0.1], [0.0, 0.0], [1.0, 1.1], [1.0, 1.0]])
# label_test = ['A', 'A', 'B', 'B']
# print(group_test)


# k-近邻算法， 输入in_x必须为一行数据，列数和data_set相同
def classify0(in_x, data_set, labels, k):
    data_set_size = data_set.shape[0]                           # 输入的数据为几行，shape为[行数，列数]，shape[0]为行数
    diff_mat = np.tile(in_x, (data_set_size, 1)) - data_set     # 把in_x的数据复制data_set_size，1列
    diff_mat = np.array(diff_mat)
    sq_diff_mat = diff_mat**2
    sq_distances = sq_diff_mat.sum(axis=1)    # 表示行相加
    distances = sq_distances**0.5
    sorted_dist_indicies = distances.argsort()  # argsort()函数是将x中的元素从小到大排列，提取其对应的index(索引)，然后输出到y
    class_count = {}
    for i in range(k):
        vote_ilabel = labels[sorted_dist_indicies[i]]
        # key -- 字典中要查找的键。
        # default -- 可选参数，如果指定键的值不存在时，返回该值，默认为 None
        class_count[vote_ilabel] = class_count.get(vote_ilabel, 0) + 1  # 如果存在，value + 1
        # 利用key进行排序，排序规则为operator.itemgetter(1)，reverse=True为降序排列
    sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
    return sorted_class_count[0][0]    #一整个大矩阵的第0行中的键值，因为value值为累计的k次中，最大的值


# 解析数据，将文本转化为numpy可以处理的矩阵
def file2matrix(filename):
    fr = open(filename)
    arrayOLines = fr.readlines()
    numberOfLines = len(arrayOLines)
    returnMat = zeros((numberOfLines, 3))
    classLabelVector = []
    index = 0
    for line in arrayOLines:
        line = line.strip()
        listFormLine = line.split('\t')
        returnMat[index, :] = listFormLine[0:3]      #[index表示行，：逗号后面的表示列]
        # print(returnMat)
        classLabelVector.append(int(listFormLine[-1]))
        index += 1
    return returnMat,classLabelVector   #分别返回数据的前三列，和最后一列

#归一特征值
def auto_norm(data_set):
    min_vals = data_set.min(0)
    max_vals = data_set.max(0)
    ranges = max_vals - min_vals
    norm_data_set = zeros(np.shape(data_set))
    m = data_set.shape[0]
    norm_data_set = data_set - np.tile(min_vals, (m, 1))
    norm_data_set = norm_data_set/np.tile(ranges, (m, 1))
    return norm_data_set, ranges, min_vals    ##返回各列转化为0-1之间的值后的矩阵，最大值与最小值差值，最小值


def dating_class_test():
    ho_ratio = 0.1
    dating_data_mat, dating_labels = file2matrix('datingTestSet2.txt')
    norm_data_set, ranges, min_vals = auto_norm(dating_data_mat)
    m = norm_data_set.shape[0]            # m=1000  样本数据集终点
    num_temp_vecs = int(m*ho_ratio)        # value is 100   自定义样本数据集从哪开始取
    error_count = 0.0
    for i in range(num_temp_vecs):
        classifier_result = classify0(norm_data_set[i, :], norm_data_set[num_temp_vecs:m, :],
                                      dating_labels[num_temp_vecs:m], 3)
        print("the classifier came back with : %d, the real answer is %d"
              % (classifier_result, dating_labels[i]))
        if classifier_result != dating_labels[i]:
            error_count += 1
    print("the error rate is  %f" % (error_count/float(num_temp_vecs)))


def classify_person():
    result_list = ['not at all', 'in small doses', 'in large doses']
    percent_tats = float(input("percentage of time spent playing video games?"))
    ff_miles = float(input("frequent flier miles earned per year?"))
    ice_cream = float(input("liters of ice cream consumed per year ?"))
    dating_data_mat, dating_labels = file2matrix('datingTestSet2.txt')
    norm_data_set, ranges, min_vals = auto_norm(dating_data_mat)
    in_arr = np.array([ff_miles, percent_tats, ice_cream])
    classifier_result = classify0(in_arr - min_vals/ranges, norm_data_set, dating_labels, 3)
    print("you will probably like this person: ", result_list[classifier_result -1])


dating_class_test()
# dating_data_mat, dating_labels = file2matrix('datingTestSet2.txt')
# norm_data_set, ranges, min_vals = auto_norm(dating_data_mat)
# fig = plt.figure()
# ax = fig.add_subplot(111)
# ax.scatter(dating_data_mat[:, 1].tolist(), dating_data_mat[:, 2].tolist(),)
# plt.show()
# plt.close()
